import { Card, Room } from "../interface";
import { broadCast, Globel, setUserScore } from "../lib/tools";
//游戏玩家
interface GamePlayer {
    username: string;
    userid: string;
    index: number;
    score: number;
    scoreNum: number;
    icon: string;
    sex: 'Man' | 'Woman';
    ready: boolean;
    isLandLord?: boolean;
    cards?: Array<Card>;
}

export default class Game {
    private cardArr: Array<Card | null> = [];
    public playerMap = new Map<string, GamePlayer>();
    //当前叫地主玩家id;
    private currentChooseLandlord: string = "";
    private current_score:number = 0;
    constructor(public room: Room) {
        // this.room.playerClients = playerArr;
        // this.playerArr = playerArr.map(v=>{
        //     let obj:GamePlayer = {
        //         userid:v.userid,
        //         score:-1,
        //         ready:false
        //     }
        //     return obj
        // });
        // this.init();
    }
    //初始化牌组并洗牌
    private init(): void {
        this.cardArr = [];
        let typeArr = ['fangkuai', 'hongtao', 'heitao', 'meihua'];
        for (let j of typeArr) {
            for (let i = 3; i < 16; i++) {
                this.cardArr.push({
                    type: j,
                    value: i
                })
            }
        }
        this.cardArr.push({ type: 'king', value: 16 })
        this.cardArr.push({ type: 'king', value: 17 })
        this.cardArr.sort(function () {
            return Math.random() - 0.5;
        })
        this.sendCard();
    }

    //发牌
    public sendCard(): void {
        let cards: Card[][] = [];
        this.playerMap.forEach(v => { cards.push([]) })
        for (let j = 0; j < this.cardArr.length - this.playerMap.size; j += this.playerMap.size) {
            for (let index = 0; index < cards.length; index++) {
                cards[index].push(this.cardArr[j + index]!)
                this.cardArr[j + index] = null;
            }
        }
        this.cardArr = this.cardArr.filter(v => v != null);
        this.playerMap.forEach((v, key) => {
            v.cards = cards[v.index];
            this.room.playerClients.get(key)!.ctx?.websocket.send(JSON.stringify({
                cmd: 'SendCard',
                userid: this.playerMap.get(key)!.userid,
                data: {
                    cards: cards[v.index],
                }
            }))
        })
        // this.playerMap.forEach((v,key)=>{
        //     this.playerMap.get(key)!.cards = cards[v.index];
        // })
        setTimeout(() => {
            this.chooseLandlord();
        }, 1000)

    }
    //随机选择叫地主的玩家
    private chooseLandlord() {
        let index = Math.floor(Math.random() * 3);
        this.playerMap.forEach(v => {
            if (v.index == index) this.currentChooseLandlord = v.userid;
        })
        broadCast({
            cmd: 'landlordplayer',
            userid: this.currentChooseLandlord,
        }, this.room.playerClients)
    }

    //玩家出牌
    public playergo(userid: string, cards: Array<Card>) {
        let user = this.playerMap.get(userid)!
        let userIndex = user.index;
        let nextIndex = 0;
        if (userIndex < 2) nextIndex = userIndex + 1;
        let next_userid = "";
        this.playerMap.forEach(v => {
            if (v.index == nextIndex) next_userid = v.userid;
        })
        let cardValueList = cards.map(v=>v.value);
        if(isBoom(cardValueList)||isKingBoom(cardValueList)) this.current_score*=2;
        broadCast({
            cmd: 'go',
            userid: userid,
            data: {
                cards: cards,
                next_userid,
                score:this.current_score
            }
        }, this.room.playerClients)
        for (let i of cards) {
            let rmIndex = user.cards!.findIndex(v => (v.type == i.type && v.value == i.value));
            user.cards!.splice(rmIndex, 1);
        }
        
        //游戏结束
        if (user.cards!.length <= 0) {
            let userCardMap: any = {};
            this.playerMap.forEach((v, key) => {
                userCardMap[key] = v.cards;
            })
            if (user.isLandLord) {
                this.playerMap.forEach(v=>{
                    if(v.userid==userid){
                        v.scoreNum+=(this.current_score*10*2)
                    }else{
                        v.scoreNum-=(this.current_score*10)
                    }
                })
                //地主胜利
                broadCast({
                    cmd: 'game-over',
                    userid: '',
                    data: {
                        win_users: [userid],
                        win_role: 'landlord',
                        userCardMap
                    }
                }, this.room.playerClients)
                
            } else {
                //农民胜利
                let userids: string[] = [];
                this.playerMap.forEach(v => {
                    if (!v.isLandLord){
                        userids.push(v.userid);
                        v.scoreNum+=(this.current_score*10)
                    }else{
                        v.scoreNum-=(this.current_score*10*2)
                    }
                })
                broadCast({
                    cmd: 'game-over',
                    userid: '',
                    data: {
                        win_users: userids,
                        win_role: 'farmer',
                        userCardMap
                    }
                }, this.room.playerClients)
            }
            let obj = {} as any;
            this.playerMap.forEach(v=>{
                obj[v.userid] = v.scoreNum;
            })
            setUserScore(obj);
            this.reset();
        }
    }

    //玩家叫分(若满足条件则选出地主)
    public playerToScore(userid: string, score: number) {
        let findPlayer = this.playerMap.get(userid)!;
        findPlayer.score = score;
        if(score>this.current_score) this.current_score = score;
        broadCast({
            cmd: 'playerToScore',
            userid: userid,
            data: {
                score: score
            }
        }, this.room.playerClients)
        if (score >= 3) {
            findPlayer.isLandLord = true;
            findPlayer.cards = findPlayer.cards!.concat(this.cardArr.filter(v => v != null) as Array<Card>)
            setTimeout(() => {
                broadCast({
                    cmd: 'landlord',
                    userid: userid,
                    data: {
                        score: score,
                        cards: this.cardArr.filter(v => v != null)
                    }
                }, this.room.playerClients)
            }, 2000);
        } else {
            let start = true;
            this.playerMap.forEach(v => { if (v.score == -1) start = false });
            if (start) {
                let max = 0;
                let max_userid = "";
                this.playerMap.forEach(v => {
                    if (v.score > max) {
                        max = v.score;
                        max_userid = v.userid;
                    }
                })
                if (max == 0) {
                    setTimeout(() => {
                        broadCast({
                            cmd: 'reset',
                            userid: '',
                            message: 'no landlord'
                        }, this.room.playerClients)
                        this.reset(true);
                    }, 1000)
                } else {
                    let landlordPlayer = this.playerMap.get(max_userid)!;
                    landlordPlayer.isLandLord = true;
                    landlordPlayer.cards = landlordPlayer.cards!.concat(this.cardArr.filter(v => v != null) as Array<Card>)
                    setTimeout(() => {
                        broadCast({
                            cmd: 'landlord',
                            userid: max_userid,
                            data: {
                                score: max,
                                cards: this.cardArr.filter(v => v != null)
                            }
                        }, this.room.playerClients)
                    }, 2000);
                }

            } else {
                let currentIndex = this.playerMap.get(this.currentChooseLandlord)!.index;
                let nextIndex = currentIndex + 1 > 2 ? 0 : currentIndex + 1;
                console.log('index', nextIndex);
                this.playerMap.forEach(v => {
                    if (v.index == nextIndex) this.currentChooseLandlord = v.userid;
                })
                broadCast({
                    cmd: 'landlordplayer',
                    userid: this.currentChooseLandlord,
                }, this.room.playerClients)
            }
        }
    }

    //玩家准备
    public playerReady(userid: string, isReady: boolean) {
        this.playerMap.get(userid)!.ready = isReady;
        broadCast({
            cmd: 'playerReady',
            userid: userid,
            data: {
                isReady
            }
        }, this.room.playerClients)
        // console.log(this.playerArr)
        if (this.playerMap.size == 3) {
            let flag = true;
            this.playerMap.forEach(v => {
                if (!v.ready) flag = false;
            })
            if (flag) this.init();
        }
    }

    //重置游戏
    public reset(isReady = false) {
        this.current_score = 0;
        this.currentChooseLandlord = "";
        this.playerMap.forEach(v => {
            v.score = -1;
            v.ready = isReady;
            v.cards = [];
            v.isLandLord = false;
        })
        if (this.playerMap.size == 3) {
            let flag = true;
            this.playerMap.forEach(v => {
                if (!v.ready) flag = false;
            })
            if (flag) this.init();
        }
    }
}

//判断是否为王炸
function isKingBoom(cardlist: number[]) {
    if ((cardlist[0] == 16 && cardlist[1] == 17) || cardlist[0] == 17 && cardlist[1] == 16) {
        return true;
    }
    else {
        return false;
    }
}

//判断炸弹
function isBoom(cardlist: number[]) {
    if(cardlist.length<4) return false;
    for (let i = 0; i < cardlist.length; i++) {
        if (cardlist[0] != cardlist[i]) return false;
    }
    return true;
}